Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Commit 62cd3977c7c79e60ca9d001ac5db99279b23b4eb


Parents : 7235fa6
Author : Mark Qvist <mark@unsigned.io>
Date : 2025-01-13T11:36:28+01:00

Added modified ST7789 driver for Heltec T114

Changes

1 files changed, 440 insertions(+), 0 deletions(-)

A ST7789.h +440

Diff

diff --git a/ST7789.h b/ST7789.h
new file mode 100644
index 0000000..85012e8
--- /dev/null
+++ b/ST7789.h
@@ -0,0 +1,440 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn
+ * Copyright (c) 2018 by Fabrice Weinberg
+ * Copyright (c) 2024 by Heltec AutoMation
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * ThingPulse invests considerable time and money to develop these open source libraries.
+ * Please support us by buying our products (and not the clones) from
+ * https://thingpulse.com
+ *
+ */
+
+#ifndef ST7789Spi_h
+#define ST7789Spi_h
+
+#include "OLEDDisplay.h"
+#include <SPI.h>
+
+
+#define ST_CMD_DELAY 0x80 // special signifier for command lists
+
+#define ST77XX_NOP 0x00
+#define ST77XX_SWRESET 0x01
+#define ST77XX_RDDID 0x04
+#define ST77XX_RDDST 0x09
+
+#define ST77XX_SLPIN 0x10
+#define ST77XX_SLPOUT 0x11
+#define ST77XX_PTLON 0x12
+#define ST77XX_NORON 0x13
+
+#define ST77XX_INVOFF 0x20
+#define ST77XX_INVON 0x21
+#define ST77XX_DISPOFF 0x28
+#define ST77XX_DISPON 0x29
+#define ST77XX_CASET 0x2A
+#define ST77XX_RASET 0x2B
+#define ST77XX_RAMWR 0x2C
+#define ST77XX_RAMRD 0x2E
+
+#define ST77XX_PTLAR 0x30
+#define ST77XX_TEOFF 0x34
+#define ST77XX_TEON 0x35
+#define ST77XX_MADCTL 0x36
+#define ST77XX_COLMOD 0x3A
+
+#define ST77XX_MADCTL_MY 0x80
+#define ST77XX_MADCTL_MX 0x40
+#define ST77XX_MADCTL_MV 0x20
+#define ST77XX_MADCTL_ML 0x10
+#define ST77XX_MADCTL_RGB 0x00
+
+#define ST77XX_RDID1 0xDA
+#define ST77XX_RDID2 0xDB
+#define ST77XX_RDID3 0xDC
+#define ST77XX_RDID4 0xDD
+
+// Some ready-made 16-bit ('565') color settings:
+#define ST77XX_BLACK 0x0000
+#define ST77XX_WHITE 0xFFFF
+#define ST77XX_RED 0xF800
+#define ST77XX_GREEN 0x07E0
+#define ST77XX_BLUE 0x001F
+#define ST77XX_CYAN 0x07FF
+#define ST77XX_MAGENTA 0xF81F
+#define ST77XX_YELLOW 0xFFE0
+#define ST77XX_ORANGE 0xFC00
+
+#define LED_A_ON LOW
+
+#ifdef ESP_PLATFORM
+#undef LED_A_ON
+#define LED_A_ON HIGH
+#define rtos_free free
+#define rtos_malloc malloc
+//SPIClass SPI1(HSPI);
+#endif
+class ST7789Spi : public OLEDDisplay {
+ private:
+ uint8_t _rst;
+ uint8_t _dc;
+ uint8_t _cs;
+ uint8_t _ledA;
+ int _miso;
+ int _mosi;
+ int _clk;
+ SPIClass * _spi;
+ SPISettings _spiSettings;
+ uint16_t _RGB=0xFFFF;
+ uint8_t _buffheight;
+ public:
+ /* pass _cs as -1 to indicate "do not use CS pin", for cases where it is hard wired low */
+ ST7789Spi(SPIClass *spiClass,uint8_t _rst, uint8_t _dc, uint8_t _cs, OLEDDISPLAY_GEOMETRY g = GEOMETRY_RAWMODE,uint16_t width=240,uint16_t height=320,int mosi=-1,int miso=-1,int clk=-1) {
+ this->_spi = spiClass;
+ this->_rst = _rst;
+ this->_dc = _dc;
+ this->_cs = _cs;
+ this->_mosi=mosi;
+ this->_miso=miso;
+ this->_clk=clk;
+ //this->_ledA = _ledA;
+ _spiSettings = SPISettings(40000000, MSBFIRST, SPI_MODE0);
+ setGeometry(g,width,height);
+ }
+
+ bool connect(){
+ this->_buffheight=displayHeight / 8;
+ this->_buffheight+=displayHeight % 8 ? 1:0;
+ pinMode(_cs, OUTPUT);
+ pinMode(_dc, OUTPUT);
+ //pinMode(_ledA, OUTPUT);
+ if (_cs != (uint8_t) -1) {
+ pinMode(_cs, OUTPUT);
+ }
+ pinMode(_rst, OUTPUT);
+
+#ifdef ESP_PLATFORM
+ _spi->begin(_clk,_miso,_mosi,-1);
+#else
+ _spi->begin();
+#endif
+ _spi->setClockDivider (SPI_CLOCK_DIV2);
+
+ // Pulse Reset low for 10ms
+ digitalWrite(_rst, HIGH);
+ delay(1);
+ digitalWrite(_rst, LOW);
+ delay(10);
+ digitalWrite(_rst, HIGH);
+ _spi->begin ();
+ //digitalWrite(_ledA, LED_A_ON);
+ return true;
+ }
+
+ void display(void) {
+ #ifdef OLEDDISPLAY_DOUBLE_BUFFER
+
+ uint16_t minBoundY = UINT16_MAX;
+ uint16_t maxBoundY = 0;
+
+ uint16_t minBoundX = UINT16_MAX;
+ uint16_t maxBoundX = 0;
+
+ uint16_t x, y;
+
+ // Calculate the Y bounding box of changes
+ // and copy buffer[pos] to buffer_back[pos];
+ for (y = 0; y < _buffheight; y++) {
+ for (x = 0; x < displayWidth; x++) {
+ //Serial.printf("x %d y %d\r\n",x,y);
+ uint16_t pos = x + y * displayWidth;
+ if (buffer[pos] != buffer_back[pos]) {
+ minBoundY = min(minBoundY, y);
+ maxBoundY = max(maxBoundY, y);
+ minBoundX = min(minBoundX, x);
+ maxBoundX = max(maxBoundX, x);
+ }
+ buffer_back[pos] = buffer[pos];
+ }
+ yield();
+ }
+
+ // If the minBoundY wasn't updated
+ // we can savely assume that buffer_back[pos] == buffer[pos]
+ // holdes true for all values of pos
+ if (minBoundY == UINT16_MAX) return;
+
+ set_CS(LOW);
+ _spi->beginTransaction(_spiSettings);
+
+ for (y = minBoundY; y <= maxBoundY; y++)
+ {
+ for(int temp = 0; temp<8;temp++)
+ {
+ //setAddrWindow(minBoundX,y*8+temp,maxBoundX-minBoundX+1,1);
+ setAddrWindow(minBoundX,y*8+temp,maxBoundX-minBoundX+1,1);
+ //setAddrWindow(y*8+temp,minBoundX,1,maxBoundX-minBoundX+1);
+ uint32_t const pixbufcount = maxBoundX-minBoundX+1;
+ uint16_t *pixbuf = (uint16_t *)rtos_malloc(2 * pixbufcount);
+ for (x = minBoundX; x <= maxBoundX; x++)
+ {
+ pixbuf[x-minBoundX] = ((buffer[x + y * displayWidth]>>temp)&0x01)==1?_RGB:0;
+ }
+#ifdef ESP_PLATFORM
+ _spi->transferBytes((uint8_t *)pixbuf, NULL, 2 * pixbufcount);
+#else
+ _spi->transfer(pixbuf, NULL, 2 * pixbufcount);
+#endif
+ rtos_free(pixbuf);
+ }
+ }
+ _spi->endTransaction();
+ set_CS(HIGH);
+
+ #else
+ set_CS(LOW);
+ _spi->beginTransaction(_spiSettings);
+ uint8_t x, y;
+ for (y = 0; y < _buffheight; y++)
+ {
+ for(int temp = 0; temp<8;temp++)
+ {
+ //setAddrWindow(minBoundX,y*8+temp,maxBoundX-minBoundX+1,1);
+ //setAddrWindow(minBoundX,y*8+temp,maxBoundX-minBoundX+1,1);
+ setAddrWindow(y*8+temp,0,1,displayWidth);
+ uint32_t const pixbufcount = displayWidth;
+ uint16_t *pixbuf = (uint16_t *)rtos_malloc(2 * pixbufcount);
+ for (x = 0; x < displayWidth; x++)
+ {
+ pixbuf[x] = ((buffer[x + y * displayWidth]>>temp)&0x01)==1?_RGB:0;
+ }
+#ifdef ESP_PLATFORM
+ _spi->transferBytes((uint8_t *)pixbuf, NULL, 2 * pixbufcount);
+#else
+ _spi->transfer(pixbuf, NULL, 2 * pixbufcount);
+#endif
+ rtos_free(pixbuf);
+ }
+ }
+ _spi->endTransaction();
+ set_CS(HIGH);
+
+ #endif
+ }
+
+ virtual void resetOrientation() {
+ uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MX;
+ sendCommand(ST77XX_MADCTL);
+ WriteData(madctl);
+ delay(10);
+ }
+
+ virtual void flipScreenVertically() {
+ uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MY;
+ sendCommand(ST77XX_MADCTL);
+ WriteData(madctl);
+ delay(10);
+ }
+
+ virtual void mirrorScreen() {
+ uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MX|ST77XX_MADCTL_MY;
+ sendCommand(ST77XX_MADCTL);
+ WriteData(madctl);
+ delay(10);
+ }
+
+ virtual void setRotation(uint8_t r) {
+ uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MX;
+ if (r == 1) { madctl = 0xC0; }
+ if (r == 2) { madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MY; }
+ if (r == 3) { madctl = 0x00; }
+ sendCommand(ST77XX_MADCTL);
+ WriteData(madctl);
+ delay(10);
+ }
+
+ void setRGB(uint16_t c)
+ {
+
+ this->_RGB=0x00|c>>8|c<<8&0xFF00;
+ }
+
+ void displayOn(void) {
+ //sendCommand(DISPLAYON);
+ }
+
+ void displayOff(void) {
+ //sendCommand(DISPLAYOFF);
+ }
+
+//#define ST77XX_MADCTL_MY 0x80
+//#define ST77XX_MADCTL_MX 0x40
+//#define ST77XX_MADCTL_MV 0x20
+//#define ST77XX_MADCTL_ML 0x10
+ protected:
+ // Send all the init commands
+ virtual void sendInitCommands()
+ {
+ sendCommand(ST77XX_SWRESET); // 1: Software reset, no args, w/delay
+ delay(150);
+
+ sendCommand(ST77XX_SLPOUT); // 2: Out of sleep mode, no args, w/delay
+ delay(10);
+
+ sendCommand(ST77XX_COLMOD); // 3: Set color mode, 16-bit color
+ WriteData(0x55);
+ delay(10);
+
+ sendCommand(ST77XX_MADCTL); // 4: Mem access ctrl (directions), Row/col addr, bottom-top refresh
+ WriteData(0x08);
+
+ sendCommand(ST77XX_CASET); // 5: Column addr set,
+ WriteData(0x00);
+ WriteData(0x00); // XSTART = 0
+ WriteData(0x00);
+ WriteData(240); // XEND = 240
+
+ sendCommand(ST77XX_RASET); // 6: Row addr set,
+ WriteData(0x00);
+ WriteData(0x00); // YSTART = 0
+ WriteData(320>>8);
+ WriteData(320&0xFF); // YSTART = 320
+
+ sendCommand(ST77XX_SLPOUT); // 7: hack
+ delay(10);
+
+ sendCommand(ST77XX_NORON); // 8: Normal display on, no args, w/delay
+ delay(10);
+
+ sendCommand(ST77XX_DISPON); // 9: Main screen turn on, no args, delay
+ delay(10);
+
+ sendCommand(ST77XX_INVON); // 10: invert
+ delay(10);
+
+ //uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MX;
+ uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MX;
+ sendCommand(ST77XX_MADCTL);
+ WriteData(madctl);
+ delay(10);
+ setRGB(ST77XX_GREEN);
+ }
+
+
+ private:
+
+ void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
+ x += (320-displayWidth)/2;
+ y += (240-displayHeight)/2;
+ uint32_t xa = ((uint32_t)x << 16) | (x + w - 1);
+ uint32_t ya = ((uint32_t)y << 16) | (y + h - 1);
+
+ writeCommand(ST77XX_CASET); // Column addr set
+ SPI_WRITE32(xa);
+
+ writeCommand(ST77XX_RASET); // Row addr set
+ SPI_WRITE32(ya);
+
+ writeCommand(ST77XX_RAMWR); // write to RAM
+ }
+ int getBufferOffset(void) {
+ return 0;
+ }
+ inline void set_CS(bool level) {
+ if (_cs != (uint8_t) -1) {
+ digitalWrite(_cs, level);
+ }
+ };
+ inline void sendCommand(uint8_t com) __attribute__((always_inline)){
+ set_CS(HIGH);
+ digitalWrite(_dc, LOW);
+ set_CS(LOW);
+ _spi->beginTransaction(_spiSettings);
+ _spi->transfer(com);
+ _spi->endTransaction();
+ set_CS(HIGH);
+ digitalWrite(_dc, HIGH);
+ }
+
+ inline void WriteData(uint8_t data) __attribute__((always_inline)){
+ digitalWrite(_cs, LOW);
+ _spi->beginTransaction(_spiSettings);
+ _spi->transfer(data);
+ _spi->endTransaction();
+ digitalWrite(_cs, HIGH);
+ }
+ void SPI_WRITE32(uint32_t l)
+ {
+ _spi->transfer(l >> 24);
+ _spi->transfer(l >> 16);
+ _spi->transfer(l >> 8);
+ _spi->transfer(l);
+ }
+ void writeCommand(uint8_t cmd) {
+ digitalWrite(_dc, LOW);
+ _spi->transfer(cmd);
+ digitalWrite(_dc, HIGH);
+ }
+
+// Private functions
+ void setGeometry(OLEDDISPLAY_GEOMETRY g, uint16_t width, uint16_t height) {
+ this->geometry = g;
+
+ switch (g) {
+ case GEOMETRY_128_128:
+ this->displayWidth = 128;
+ this->displayHeight = 128;
+ break;
+ case GEOMETRY_128_64:
+ this->displayWidth = 128;
+ this->displayHeight = 64;
+ break;
+ case GEOMETRY_128_32:
+ this->displayWidth = 128;
+ this->displayHeight = 32;
+ break;
+ case GEOMETRY_64_48:
+ this->displayWidth = 64;
+ this->displayHeight = 48;
+ break;
+ case GEOMETRY_64_32:
+ this->displayWidth = 64;
+ this->displayHeight = 32;
+ break;
+ case GEOMETRY_RAWMODE:
+ this->displayWidth = width > 0 ? width : 128;
+ this->displayHeight = height > 0 ? height : 64;
+ break;
+ }
+ uint8_t tmp=displayHeight % 8;
+ uint8_t _buffheight=displayHeight / 8;
+
+ if(tmp!=0)
+ _buffheight++;
+ this->displayBufferSize = displayWidth * _buffheight ;
+ }
+
+
+
+};
+
+#endif
\ No newline at end of file


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────